package compile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import plugin.CompileClassLoader;

import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 动态编译类 具有动态编译功能 并且聚合了所需要的资源类
 */
public class DynamicJavaCompile implements Compile {

    public static final Logger logger = LoggerFactory.getLogger(DynamicJavaCompile.class);
    /**
     * 编译工具
     */
    private static JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    /**
     * 临时文件存储路径
     */
    private static Path tempPath;

    /**
     * 文件路径分隔符
     */
    private static final String fileSeparator = File.separator;

    static {
        // 根据操作系统选择临时目录
        String userHomeDir = System.getProperty("user.home");
        tempPath = Paths.get(userHomeDir, "temp");
        try {
            Files.createDirectories(tempPath);
        } catch (IOException e) {
            logger.error("创建目录或加载目录失败,异常原因:{}",e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public Class<?> compile(String sourceCode,String className) throws IOException, ClassNotFoundException {
        File file = new File(tempPath.toString() + fileSeparator +  className + ".java");
        Path tempFile;
        if(file == null){
            tempFile = Files.createFile(tempPath.resolve(className + ".java"));
        } else {
            tempFile = file.toPath();
        }
        Files.writeString(tempFile,sourceCode);
        Class<?> compileClass = dynamicCompile(tempFile);
        // 删除临时工作目录以及文件
        logger.info("即将递归删除目录:{}",tempPath.toString());
        deleteDirectoryRecursively(tempPath);
        return compileClass;
    }

    /**
     * 递归删除指定目录及其所有子目录和文件。
     *
     * @param directory 要删除的目录路径
     * @throws IOException 如果在删除过程中发生I/O错误
     */
    private static void deleteDirectoryRecursively(Path directory) throws IOException {
        if (!Files.isDirectory(directory)) {
            throw new IllegalArgumentException(directory + " 不是一个有效的目录");
        }

        // 遍历目录下的所有文件和子目录
        try (var stream = Files.list(directory)) {
            for (Path entry : stream.collect(Collectors.toList())) {
                if (Files.isDirectory(entry)) {
                    // 如果是子目录，递归删除
                    deleteDirectoryRecursively(entry);
                } else {
                    // 如果是文件，直接删除
                    Files.delete(entry);
                }
            }
        }

        // 当所有内容都被删除后，删除空的父目录
        Files.delete(directory);
    }

    @Override
    public Class<?> compile(File javaFile) throws IOException, ClassNotFoundException {
        Path path = javaFile.toPath();
        return dynamicCompile(path);
    }

    private Class<?> dynamicCompile(Path javaFile) throws IOException, ClassNotFoundException {
        // 编译期间诊断信息处理器
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, StandardCharsets.UTF_8);
        List<String> options = new ArrayList<>();
        // 输出目录
        options.add("-d");
        options.add(javaFile.getParent().toString());
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(javaFile.getParent().toFile()));
        // 获取 java 文件对象
        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(javaFile.toFile());
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);

        Boolean success = task.call();
        // 检查编译是否成功
        if (!success) {
            logger.error("Compilation failed");
            for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                System.err.format("Error on line %d in %s%n",
                        diagnostic.getLineNumber(), diagnostic.getSource().toUri());
            }
            throw new IllegalStateException("Compilation failed");
        }

        //加载编译后的字节码文件
        CompileClassLoader compileClassLoader = new CompileClassLoader(javaFile.getParent().toString());
        //获取类名
        String filename = javaFile.getFileName().toString();
        String name = filename.substring(0, filename.lastIndexOf("."));
        return compileClassLoader.loadClass(name);
    }

//    public static void main(String[] args) throws IOException {
//        deleteDirectoryRecursively(tempPath);
//    }


}
